package com.wyfan.scaffold.test;

import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 计算任务父类
 * 每个计算任务子类如果被实例化请确保任务对象有且只被1处计算，否则会影响计算链路 taskCountDownLatch 的计数，造成链路阻塞超时
 */
@Slf4j
public abstract class CalTaskAbstract implements Runnable, Comparable<CalTaskAbstract>{

    static AtomicInteger TASK_COUNT = new AtomicInteger(0);
    private static Map<String,Boolean> TASK_MAP = new HashMap<>();


    /** 计算链路门栓 */
    private final CountDownLatch taskCountDownLatch;
    /** 是否执行计算任务 */
    private boolean submit;
    /** 任务优先级， 数值越小任务优先级越高 */
    private long order;

//    static {
//        Set<Class<?>> hasCalAnnaClass;
//        Class calTaskAbstractClass;
//        // 扫描 Cal 注解的类
//        Reflections reflections = new Reflections("com.wyfan.scaffold");
//        hasCalAnnaClass = reflections.getTypesAnnotatedWith(Cal.class);
        // 含 Cal 注解的类实例化时加入任务链路统计，用于 CountDownLatch 进行标志结束计算
//        hasCalAnnaClass.forEach(clazz -> {
//            Annotation[] annotations = clazz.getAnnotations();
//            for (Annotation annotation : annotations) {
//                if (annotation instanceof Cal) {
//                    if (((Cal) annotation).submit()) {
//                        Boolean task = TASK_MAP.putIfAbsent(clazz.getName(),true);
//                        if (task == null) {
//                            int count = TASK_COUNT.incrementAndGet();
//                            log.warn(clazz.getSimpleName()+" 加入任务统计,请确保任务对象只被实例化1次，并提交到任务队列,"+"当前计算任务数达到 "+count);
//                        }
//                    }
//                }
//            }
//        });
//    }


    public CalTaskAbstract(CountDownLatch taskCountDownLatch, boolean submit, long order) {
        this.taskCountDownLatch = taskCountDownLatch;
        this.submit = submit;
        this.order = order;
    }

    @Override
    public void run() {
        // 实例化时加入任务链路统计，用于 CountDownLatch 进行标志结束计算
        // 非线程安全， 链路初始化调用能避免线程安全
        Boolean task = TASK_MAP.putIfAbsent(this.getClass().getName(),true);
        if (task == null) {
            int count = TASK_COUNT.incrementAndGet();
            log.warn(this.getClass().getSimpleName()+" 加入任务统计,请确保任务对象有且只被1处计算,"+"当前计算链路任务数 "+count);
        }

        // 执行任务
        try {
            if (submit) {
                execute();
            }
        } catch (Exception e) {
            log.error("任务执行失败：" + this.getClass().getSimpleName(),e);
        } finally {
            taskCountDownLatch.countDown();
        }
    }

    public abstract void execute();


    @Override
    public int compareTo(CalTaskAbstract o) {
        // 复写此方法进行任务执行优先级排序, order 小的先计算
        return Long.compare(this.order,o.order);
    }

}
